/**** File Info Stats ****
 *usage:
 *  Statistic file info based on given <dir> and file limit
 *
 * Created by Li Zhou, Apr 23
 */

#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>

/** Define constant value for K bytes **/
#define KB 1024


/** Traverse function **/
int traverse(const char * path, const int limit, int * total, int * big_file_cnt ) {
	struct dirent * entry = NULL;
    DIR * pDir;
	/** to be scaned directory path **/
	char * to_do_dir = malloc(PATH_MAX);
	/** file name **/
	char * ptr_file  = malloc(PATH_MAX);

	/********************* Start ***********************/
	pDir = opendir(path);
	/** error proc **/
	if( pDir == NULL ) {
		perror("open dir failed");
		return -1;
	}
	
	while ( (entry = readdir(pDir)) != NULL ) {
		/* Regular file */
		if( entry->d_type == DT_REG ) {
			memset(ptr_file, 0, PATH_MAX);
			// if file name is too long
         	if(strlen(path) + strlen(entry->d_name) + 1 > PATH_MAX)
	        	return;
            /* Construct the complete file path */ 
			strcpy(ptr_file, path);
			strcat(ptr_file, "/");
			strcat(ptr_file, entry->d_name);
			/* count file number */
			(*total)++;

			struct stat st_info;
			stat(ptr_file, &st_info);
			/* if match the size requirement */
			if(st_info.st_size >= limit * KB ) {
				(*big_file_cnt)++;
				printf(" %s,\t\t%.2f kb. \n", 
						ptr_file,
						st_info.st_size*1.00/KB);
			}
		}
		/* Directory */
		else if(entry->d_type == DT_DIR) {
			memset(to_do_dir, 0, PATH_MAX);
			/* Ignor ./   &   ../    */
			if( strcmp(entry->d_name, ".") == 0 
			  ||strcmp(entry->d_name, "..") == 0
			  )
				continue;
			// path is too long
         	if(strlen(path) + strlen(entry->d_name) + 1 > PATH_MAX) {
				perror("Path too long");
	        	return -1;
			}
			/* construct the absolute directory path */
	        strcpy(to_do_dir, path);
			strcat(to_do_dir, "/");
			strcat(to_do_dir, entry->d_name);
			if(traverse(to_do_dir, limit, total, big_file_cnt) == -1)
				return -1;
		}
		/* other type */
		else {	
			fprintf(stderr, "Not file & Not directory\n");
		}
	}
	/* Clean resource */
	free(to_do_dir);
	free(ptr_file);
	to_do_dir = NULL;
	ptr_file = NULL;
	closedir(pDir);
}


/******** Main function ***********/

int main(int argc, char * argv[]) {
    if(argc != 3) {
		fprintf(stderr, "%s <limit> <directory>\n", argv[0]);
		fprintf(stderr, "limit - size of file, kb\n");
		return -1;
	}
	/* get limit */
	int limit = atoi(argv[1]);
	/* record the number of file whose size is over limit */
	int big_file = 0;
	/* all regular file scaned */
	int total = 0;


	char * base = malloc(PATH_MAX);
	memset(base, 0 , PATH_MAX);
	/* absolute path */
	if( argv[2][0] == '/' || argv[2][0] == '~' ) {
		strcpy(base, argv[2]);
	    printf("Given path is an absolute path:  %s\n", argv[2]);
	}
	/* relative path */
	else {
	    strcpy(base, getenv("PWD"));
		printf("Given path is an relative path: %s\n", argv[2]);
        if(strlen(base) + strlen(argv[2]) + 1 > PATH_MAX)
		    return -1;
		strcat(base, "/");
	    strcat(base, argv[2]);
    }
	printf("Start at Dir: %s\n", base);
	traverse(base, limit, &total, &big_file);
	printf("Total File: %d\n", total);
	printf("Size larger than %d kb File: %d\n", limit, big_file);
    return 0;
}


